/*
 * Copyright (c) 2014-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

package com.facebook.stetho.inspector.database;

import android.annotation.TargetApi;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import androidx.annotation.IntDef;

/**
 * Compatibility layer which supports opening databases with WAL and foreign key support where
 * supported.
 *
 * <p>For simplicity of implementation, all options are <em>ignored</em> prior to Honeycomb.
 */
public abstract class SQLiteDatabaseCompat {
    public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x1;
    public static final int ENABLE_FOREIGN_KEY_CONSTRAINTS = 0x2;
    private static final SQLiteDatabaseCompat sInstance;

    static {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            sInstance = new JellyBeanAndBeyondImpl();
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            sInstance = new HoneycombImpl();
        } else {
            sInstance = new NoopImpl();
        }
    }

    public static SQLiteDatabaseCompat getInstance() {
        return sInstance;
    }

    public abstract int provideOpenFlags(@SQLiteOpenOptions int openOptions);

    public abstract void enableFeatures(@SQLiteOpenOptions int openOptions, SQLiteDatabase db);

    @IntDef(
            value = {ENABLE_WRITE_AHEAD_LOGGING, ENABLE_FOREIGN_KEY_CONSTRAINTS},
            flag = true)
    public @interface SQLiteOpenOptions {
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private static class JellyBeanAndBeyondImpl extends SQLiteDatabaseCompat {
        @Override
        public int provideOpenFlags(@SQLiteOpenOptions int openOptions) {
            int openFlags = 0;
            if ((openOptions & ENABLE_WRITE_AHEAD_LOGGING) != 0) {
                openFlags |= SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING;
            }
            return openFlags;
        }

        @Override
        public void enableFeatures(@SQLiteOpenOptions int openOptions, SQLiteDatabase db) {
            if ((openOptions & ENABLE_FOREIGN_KEY_CONSTRAINTS) != 0) {
                db.setForeignKeyConstraintsEnabled(true);
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private static class HoneycombImpl extends SQLiteDatabaseCompat {
        @Override
        public int provideOpenFlags(@SQLiteOpenOptions int openOptions) {
            return 0;
        }

        @Override
        public void enableFeatures(@SQLiteOpenOptions int openOptions, SQLiteDatabase db) {
            if ((openOptions & ENABLE_WRITE_AHEAD_LOGGING) != 0) {
                db.enableWriteAheadLogging();
            }

            if ((openOptions & ENABLE_FOREIGN_KEY_CONSTRAINTS) != 0) {
                db.execSQL("PRAGMA foreign_keys = ON");
            }
        }
    }

    private static class NoopImpl extends SQLiteDatabaseCompat {
        @Override
        public int provideOpenFlags(@SQLiteOpenOptions int openOptions) {
            return 0;
        }

        @Override
        public void enableFeatures(@SQLiteOpenOptions int openOptions, SQLiteDatabase db) {
        }
    }
}
